/*
 * Copyright (c) 2020-2021, SERI Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-05-22     Lyons        first version
 */

module pa_fpu_xfrac_pre_lop (
    expn_mask_i,
    xfrac_rnd_src0_i,
    xfrac_rnd_src1_i,
    expn_adjust_single_o,
    expn_adjust_double_o,
    xfrac_shift_low_o,
    xfrac_shift_high_o
    );

//width of xfrac_rnd is 57-bits
//include: hidden:1 + frac:52 + grs:3 for double
//include: zero:29 + hidden:1 + frac:23 + grs:3 for single

input               expn_mask_i;
input               xfrac_rnd_src0_i;
input               xfrac_rnd_src1_i;
output              expn_adjust_single_o;
output              expn_adjust_double_o;
output              xfrac_shift_low_o;
output              xfrac_shift_high_o;

wire [56:0]         expn_mask_i;
wire [56:0]         xfrac_rnd_src0_i;
wire [56:0]         xfrac_rnd_src1_i;
wire [5:0]          expn_adjust_single_o;
wire [5:0]          expn_adjust_double_o;
wire [2:0]          xfrac_shift_low_o;
wire [3:0]          xfrac_shift_high_o;


reg  [4:0]          expn_adjust_single_out;
reg  [5:0]          expn_adjust_double_out;
reg  [2:0]          xfrac_shift_low_out;
reg  [3:0]          xfrac_shift_high_out;

wire [56:0]         A;
wire [56:0]         A_nor;
wire [56:0]         B;
wire [56:0]         B_nor;
wire [56:0]         g;
wire [56:0]         e;
wire [56:0]         s;
wire [56:0]         f;
wire [56:0]         f_final;


assign A[56:0] = xfrac_rnd_src0_i[56:0];
assign A_nor[56:0] = ~A[56:0];

assign B[56:0] = xfrac_rnd_src1_i[56:0];
assign B_nor[56:0] = ~B[56:0];

assign g[56:0] = A[56:0] & B_nor[56:0];
assign e[56:0] = A[56:0] ^ B_nor[56:0];
assign s[56:0] = A_nor[56:0] & B[56:0];

assign f[0]    =  e[1] & (g[0] | s[0])
               | ~e[1] & (s[0] | g[0]);

assign f[55:1] =  e[56:2] & ( g[55:1] & ~s[54:0]
                            | s[55:1] & ~g[54:0] )
               | ~e[56:2] & ( s[55:1] & ~s[54:0]
                            | g[55:1] & ~g[54:0] );

assign f[56]   =  g[56] & ~s[55]
               |  s[56] & ~g[55];

assign f_final[56:0] = f[56:0] | expn_mask_i[56:0];

always @ (f_final[56:0]) begin
casez (f_final[56:0])
    57'b1_????????_????????_????????_????????_????????_????????_???????? : begin //not enter here with sub
        xfrac_shift_high_out[3:0]   = 4'd0;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd0;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_1???????_????????_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd0;
        xfrac_shift_low_out[2:0]    = 3'b001; //because bit[55] is hidden interger, remove after shifted
        expn_adjust_double_out[5:0] = 6'd0;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_01??????_????????_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd0;
        xfrac_shift_low_out[2:0]    = 3'b010;
        expn_adjust_double_out[5:0] = 6'd1;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_001?????_????????_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd0;
        xfrac_shift_low_out[2:0]    = 3'b100;
        expn_adjust_double_out[5:0] = 6'd2;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_0001????_????????_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd1;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd3;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00001???_????????_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd1;
        xfrac_shift_low_out[2:0]    = 3'b001;
        expn_adjust_double_out[5:0] = 6'd4;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_000001??_????????_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd1;
        xfrac_shift_low_out[2:0]    = 3'b010;
        expn_adjust_double_out[5:0] = 6'd5;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_0000001?_????????_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd1;
        xfrac_shift_low_out[2:0]    = 3'b100;
        expn_adjust_double_out[5:0] = 6'd6;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000001_????????_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd2;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd7;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_1???????_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd2;
        xfrac_shift_low_out[2:0]    = 3'b001;
        expn_adjust_double_out[5:0] = 6'd8;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_01??????_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd2;
        xfrac_shift_low_out[2:0]    = 3'b010;
        expn_adjust_double_out[5:0] = 6'd9;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_001?????_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd2;
        xfrac_shift_low_out[2:0]    = 3'b100;
        expn_adjust_double_out[5:0] = 6'd10;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_0001????_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd3;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd11;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00001???_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd3;
        xfrac_shift_low_out[2:0]    = 3'b001;
        expn_adjust_double_out[5:0] = 6'd12;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_000001??_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd3;
        xfrac_shift_low_out[2:0]    = 3'b010;
        expn_adjust_double_out[5:0] = 6'd13;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_0000001?_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd3;
        xfrac_shift_low_out[2:0]    = 3'b100;
        expn_adjust_double_out[5:0] = 6'd14;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000001_????????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd4;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd15;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000000_1???????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd4;
        xfrac_shift_low_out[2:0]    = 3'b001;
        expn_adjust_double_out[5:0] = 6'd16;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000000_01??????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd4;
        xfrac_shift_low_out[2:0]    = 3'b010;
        expn_adjust_double_out[5:0] = 6'd17;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000000_001?????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd4;
        xfrac_shift_low_out[2:0]    = 3'b100;
        expn_adjust_double_out[5:0] = 6'd18;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000000_0001????_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd5;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd19;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000000_00001???_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd5;
        xfrac_shift_low_out[2:0]    = 3'b001;
        expn_adjust_double_out[5:0] = 6'd20;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000000_000001??_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd5;
        xfrac_shift_low_out[2:0]    = 3'b010;
        expn_adjust_double_out[5:0] = 6'd21;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000000_0000001?_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd5;
        xfrac_shift_low_out[2:0]    = 3'b100;
        expn_adjust_double_out[5:0] = 6'd22;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000000_00000001_????????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd6;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd23;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000000_00000000_1???????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd6;
        xfrac_shift_low_out[2:0]    = 3'b001;
        expn_adjust_double_out[5:0] = 6'd24;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000000_00000000_01??????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd6;
        xfrac_shift_low_out[2:0]    = 3'b010;
        expn_adjust_double_out[5:0] = 6'd25;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000000_00000000_001?????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd6;
        xfrac_shift_low_out[2:0]    = 3'b100;
        expn_adjust_double_out[5:0] = 6'd26;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000000_00000000_0001????_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd7;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd27;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000000_00000000_00001???_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd7;
        xfrac_shift_low_out[2:0]    = 3'b001;
        expn_adjust_double_out[5:0] = 6'd28;
        expn_adjust_single_out[4:0] = 5'd0;
    end
    57'b0_00000000_00000000_00000000_000001??_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd7;
        xfrac_shift_low_out[2:0]    = 3'b010;
        expn_adjust_double_out[5:0] = 6'd29;
        expn_adjust_single_out[4:0] = 5'd0;
    end

//single adjust start work

    57'b0_00000000_00000000_00000000_0000001?_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd7;
        xfrac_shift_low_out[2:0]    = 3'b100;
        expn_adjust_double_out[5:0] = 6'd30;
        expn_adjust_single_out[4:0] = 5'd1;
    end
    57'b0_00000000_00000000_00000000_00000001_????????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd8;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd31;
        expn_adjust_single_out[4:0] = 5'd2;
    end
    57'b0_00000000_00000000_00000000_00000000_1???????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd8;
        xfrac_shift_low_out[2:0]    = 3'b001;
        expn_adjust_double_out[5:0] = 6'd32;
        expn_adjust_single_out[4:0] = 5'd3;
    end
    57'b0_00000000_00000000_00000000_00000000_01??????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd8;
        xfrac_shift_low_out[2:0]    = 3'b010;
        expn_adjust_double_out[5:0] = 6'd33;
        expn_adjust_single_out[4:0] = 5'd4;
    end
    57'b0_00000000_00000000_00000000_00000000_001?????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd8;
        xfrac_shift_low_out[2:0]    = 3'b100;
        expn_adjust_double_out[5:0] = 6'd34;
        expn_adjust_single_out[4:0] = 5'd5;
    end
    57'b0_00000000_00000000_00000000_00000000_0001????_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd9;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd35;
        expn_adjust_single_out[4:0] = 5'd6;
    end
    57'b0_00000000_00000000_00000000_00000000_00001???_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd9;
        xfrac_shift_low_out[2:0]    = 3'b001;
        expn_adjust_double_out[5:0] = 6'd36;
        expn_adjust_single_out[4:0] = 5'd7;
    end
    57'b0_00000000_00000000_00000000_00000000_000001??_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd9;
        xfrac_shift_low_out[2:0]    = 3'b010;
        expn_adjust_double_out[5:0] = 6'd37;
        expn_adjust_single_out[4:0] = 5'd8;
    end
    57'b0_00000000_00000000_00000000_00000000_0000001?_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd9;
        xfrac_shift_low_out[2:0]    = 3'b100;
        expn_adjust_double_out[5:0] = 6'd38;
        expn_adjust_single_out[4:0] = 5'd9;
    end
    57'b0_00000000_00000000_00000000_00000000_00000001_????????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd10;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd39;
        expn_adjust_single_out[4:0] = 5'd10;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_1???????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd10;
        xfrac_shift_low_out[2:0]    = 3'b001;
        expn_adjust_double_out[5:0] = 6'd40;
        expn_adjust_single_out[4:0] = 5'd11;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_01??????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd10;
        xfrac_shift_low_out[2:0]    = 3'b010;
        expn_adjust_double_out[5:0] = 6'd41;
        expn_adjust_single_out[4:0] = 5'd12;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_001?????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd10;
        xfrac_shift_low_out[2:0]    = 3'b100;
        expn_adjust_double_out[5:0] = 6'd42;
        expn_adjust_single_out[4:0] = 5'd13;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_0001????_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd11;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd43;
        expn_adjust_single_out[4:0] = 5'd14;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_00001???_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd11;
        xfrac_shift_low_out[2:0]    = 3'b001;
        expn_adjust_double_out[5:0] = 6'd44;
        expn_adjust_single_out[4:0] = 5'd15;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_000001??_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd11;
        xfrac_shift_low_out[2:0]    = 3'b010;
        expn_adjust_double_out[5:0] = 6'd45;
        expn_adjust_single_out[4:0] = 5'd16;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_0000001?_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd11;
        xfrac_shift_low_out[2:0]    = 3'b100;
        expn_adjust_double_out[5:0] = 6'd46;
        expn_adjust_single_out[4:0] = 5'd17;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_00000001_???????? : begin
        xfrac_shift_high_out[3:0]   = 4'd12;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd47;
        expn_adjust_single_out[4:0] = 5'd18;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_00000000_1??????? : begin
        xfrac_shift_high_out[3:0]   = 4'd12;
        xfrac_shift_low_out[2:0]    = 3'b001;
        expn_adjust_double_out[5:0] = 6'd48;
        expn_adjust_single_out[4:0] = 5'd19;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_00000000_01?????? : begin
        xfrac_shift_high_out[3:0]   = 4'd12;
        xfrac_shift_low_out[2:0]    = 3'b010;
        expn_adjust_double_out[5:0] = 6'd49;
        expn_adjust_single_out[4:0] = 5'd20;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_00000000_001????? : begin
        xfrac_shift_high_out[3:0]   = 4'd12;
        xfrac_shift_low_out[2:0]    = 3'b100;
        expn_adjust_double_out[5:0] = 6'd50;
        expn_adjust_single_out[4:0] = 5'd21;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_00000000_0001???? : begin
        xfrac_shift_high_out[3:0]   = 4'd13;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd51;
        expn_adjust_single_out[4:0] = 5'd22;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_00000000_00001??? : begin
        xfrac_shift_high_out[3:0]   = 4'd13;
        xfrac_shift_low_out[2:0]    = 3'b001;
        expn_adjust_double_out[5:0] = 6'd52;
        expn_adjust_single_out[4:0] = 5'd23;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_00000000_000001?? : begin
        xfrac_shift_high_out[3:0]   = 4'd13;
        xfrac_shift_low_out[2:0]    = 3'b010;
        expn_adjust_double_out[5:0] = 6'd53;
        expn_adjust_single_out[4:0] = 5'd24;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_00000000_0000001? : begin
        xfrac_shift_high_out[3:0]   = 4'd13;
        xfrac_shift_low_out[2:0]    = 3'b100;
        expn_adjust_double_out[5:0] = 6'd54;
        expn_adjust_single_out[4:0] = 5'd25;
    end
    57'b0_00000000_00000000_00000000_00000000_00000000_00000000_00000001 : begin
        xfrac_shift_high_out[3:0]   = 4'd14;
        xfrac_shift_low_out[2:0]    = 3'b000;
        expn_adjust_double_out[5:0] = 6'd55;
        expn_adjust_single_out[4:0] = 5'd26;
    end
    default : begin
        xfrac_shift_high_out[3:0]   = {57{1'bx}};
        xfrac_shift_low_out[2:0]    = {3{1'bx}};
        expn_adjust_double_out[5:0] = {6{1'bx}};
        expn_adjust_single_out[4:0] = {5{1'bx}};
    end
endcase
end

assign expn_adjust_double_o[5:0] = expn_adjust_double_out[5:0];
assign expn_adjust_single_o[5:0] = {1'b0, expn_adjust_single_out[4:0]};

assign xfrac_shift_high_o[3:0] = xfrac_shift_high_out[3:0];
assign xfrac_shift_low_o[2:0] = xfrac_shift_low_out[2:0];

endmodule